package com.hzk.controller;

import com.hzk.config.RedisLimitRateWithLUA;
import com.hzk.config.RequireLogin;
import com.hzk.mapper.GoodsMapper;
import com.hzk.pojo.SeckillMessage;
import com.hzk.pojo.SeckillOrder;
import com.hzk.pojo.UserBasic;
import com.hzk.rabbitmq.MQSender;
import com.hzk.service.*;
import com.hzk.utils.IDCardUtil;
import com.hzk.utils.JsonUtil;
import com.hzk.utils.ageutils;
import javax.validation.Valid;
import com.hzk.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author jack
 * @since 2022-03-01
 */
@Controller
@RequestMapping("/secKill")
@Slf4j
public class  SeckillController implements InitializingBean {
    @Autowired
    ISeckillOrderService iSeckillOrderService;
    @Autowired
    IGoodsService iGoodsService;
    @Autowired
    IUserBasicService iUserBasicService;
    @Autowired
    IOrderService iOrderService;
    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    MQSender mqSender;
    @Autowired
    private DefaultRedisScript<Long> script;
    @Autowired
    private IGoodsService goodsService;

    private Map<Long, Boolean> EmptyStockMap = new HashMap<>();

   /* @RequireLogin(seconds = 5, maxCount = 5, needLogin = true)
    @RequestMapping( value = "/doSecKill",method = RequestMethod.POST)
    @ResponseBody
    public RespBean doSeckill(@CaseUser UserBasic userBasic, @Valid cardfrom cardfrom , HttpServletRequest request) {
        UserBasic user = iUserBasicService.getById(userBasic.getId());
        if (user == null) {
            return RespBean.error(RespBeanEnum.NULL_USER_ERROR);
        }


        if (!user.getUsername().equals(cardfrom.getName())) {
            return RespBean.error(RespBeanEnum.NAME_ERROR);
        }
        if (!IDCardUtil.isIDNumber(cardfrom.getIdentity())) {
            return RespBean.error(RespBeanEnum.ID_ERROR);
        }
        if (!ageutils.evaluate(cardfrom.getIdentity()).equals(user.getAge()+"")){
            return RespBean.error(RespBeanEnum.ID2_ERROR);
        }
        if (cardfrom.getCardpwd().equals(user.getCardpwd())){
            return RespBean.error(RespBeanEnum.pwd_ERROR);
        }
        *//**
         * 分布式限流
         *//*
      *//*  try {
            RedisLimitRateWithLUA.accquire();
        } catch (IOException e) {
            return RespBean.error(RespBeanEnum.p_ERROR);
        } catch (URISyntaxException e) {
            return RespBean.error(RespBeanEnum.p_ERROR);

        }
*//*

        ValueOperations valueOperations = redisTemplate.opsForValue();

        if (redisTemplate.hasKey("seckillorder:" + user.getId() + ":" + cardfrom.getGoodsId())){
            return RespBean.error(RespBeanEnum.RESECKILL_ERROR);
        }
        String requestURI = request.getRequestURI();
        *//*captcha="0";*//*
        Integer count = (Integer)valueOperations.get(requestURI + ":" + user.getId());
        if(count==null){
            valueOperations.set(requestURI+":"+user.getId(),1,120, TimeUnit.SECONDS);
        }else if (count<5){
            valueOperations.increment(requestURI+":"+user.getId());
        }else {
            return RespBean.error(RespBeanEnum.SECKILL_REFULS);
        }
        Long goodsId = cardfrom.getGoodsId();
        //判断是否重复抢购
        SeckillOrder seckillOrderJson = (SeckillOrder) valueOperations.get("seckillorder:" +
                user.getId() + ":" + goodsId);
        if (seckillOrderJson!=null) {
            return RespBean.error(RespBeanEnum.RESECKILL_ERROR);
        }
        //判断是否为空
        if (redisTemplate.hasKey("isStockEmpty:" + goodsId)){
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
        }
        //内存标记,减少Redis访问
        if (EmptyStockMap.get(goodsId)) {
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
        }
        GoodsVo goods = goodsService.findGoodsByid(goodsId);
        UserBasic byId = iUserBasicService.getById(user.getId());
        if (byId.getCardMoney()<cardfrom.getMoney()){
            return RespBean.error(RespBeanEnum.a_ERROR);
        }
        //判断库存
        if (goods.getStockCount() < 1) {
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
            *//*throw new GabalException(RespBeanEnum.NULLGOODS_ERROR);*//*

        }
        //预减库存
        //如果庫存不足就在這裏直接返回
        // 请求入队，立即返回排队中
        SeckillMessage message = new SeckillMessage(user, goodsId,cardfrom.getMoney());
        mqSender.sendsecKillMessage(JsonUtil.object2JsonStr(message));

        Long stock = (Long) redisTemplate.execute(script,
                Collections.singletonList("seckillGoods:" + goodsId), Collections.EMPTY_LIST);
        if (stock<1) {
            Integer stockCount = iGoodsService.findGoodsByid(goodsId).getStockCount();
            if(stockCount >0){
                valueOperations.set("seckillGoods:" + goodsId,stockCount);
            }else {
                valueOperations.set("isStockEmpty:" + goodsId, "0");
                EmptyStockMap.put(goodsId, true);
                *//*valueOperations.increment("seckillGoods:" + goodsId);*//*
                return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
            }
        }
        return RespBean.success(0);
    }*/


    @RequireLogin(seconds = 5, maxCount = 5, needLogin = true)
    @RequestMapping( value = "/{path}/doSecKill",method = RequestMethod.POST)
    @ResponseBody
    public RespBean doSeckill(@CaseUser UserBasic userBasic, @PathVariable String path, @Valid cardfrom cardfrom , HttpServletRequest request) {
        UserBasic user = iUserBasicService.getById(userBasic.getId());
        if (user == null) {
            return RespBean.error(RespBeanEnum.NULL_USER_ERROR);
        }


        if (!user.getUsername().equals(cardfrom.getName())) {
            return RespBean.error(RespBeanEnum.NAME_ERROR);
        }
        if (!IDCardUtil.isIDNumber(cardfrom.getIdentity())) {
            return RespBean.error(RespBeanEnum.ID_ERROR);
        }
        if (!ageutils.evaluate(cardfrom.getIdentity()).equals(user.getAge()+"")){
            return RespBean.error(RespBeanEnum.ID2_ERROR);
        }
        if (cardfrom.getCardpwd().equals(user.getCardpwd())){
            return RespBean.error(RespBeanEnum.pwd_ERROR);
        }
        /**
         * 分布式限流
         */


        ValueOperations valueOperations = redisTemplate.opsForValue();

        if (redisTemplate.hasKey("seckillorder:" + user.getId() + ":" + cardfrom.getGoodsId())){
            return RespBean.error(RespBeanEnum.RESECKILL_ERROR);
        }
        String requestURI = request.getRequestURI();
        /*captcha="0";*/
        Integer count = (Integer)valueOperations.get(requestURI + ":" + user.getId());
        if(count==null){
            valueOperations.set(requestURI+":"+user.getId(),1,120, TimeUnit.SECONDS);
        }else if (count<5){
            valueOperations.increment(requestURI+":"+user.getId());
        }else {
            return RespBean.error(RespBeanEnum.SECKILL_REFULS);
        }
        Long goodsId = cardfrom.getGoodsId();
        //判断是否重复抢购
        SeckillOrder seckillOrderJson = (SeckillOrder) valueOperations.get("seckillorder:" +
                user.getId() + ":" + goodsId);
        if (seckillOrderJson!=null) {
            return RespBean.error(RespBeanEnum.RESECKILL_ERROR);
        }
        //判断是否为空
        if (redisTemplate.hasKey("isStockEmpty:" + goodsId)){
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
        }
        //内存标记,减少Redis访问
        if (EmptyStockMap.get(goodsId)) {
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
        }
        GoodsVo goods = goodsService.findGoodsByid(goodsId);
        UserBasic byId = iUserBasicService.getById(user.getId());
        if (byId.getCardMoney()<cardfrom.getMoney()){
            return RespBean.error(RespBeanEnum.a_ERROR);
        }
        //判断库存
        if (goods.getStockCount() < 1) {
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
            /*throw new GabalException(RespBeanEnum.NULLGOODS_ERROR);*/

        }
        //预减库存
        //如果庫存不足就在這裏直接返回
        // 请求入队，立即返回排队中
        SeckillMessage message = new SeckillMessage(user, goodsId,cardfrom.getMoney());
        mqSender.sendsecKillMessage(JsonUtil.object2JsonStr(message));

        Long stock = (Long) redisTemplate.execute(script,
                Collections.singletonList("seckillGoods:" + goodsId), Collections.EMPTY_LIST);
        if (stock<1) {
            Integer stockCount = iGoodsService.findGoodsByid(goodsId).getStockCount();
            if(stockCount >0){
                valueOperations.set("seckillGoods:" + goodsId,stockCount);
            }else {
                valueOperations.set("isStockEmpty:" + goodsId, "0");
                EmptyStockMap.put(goodsId, true);
                /*valueOperations.increment("seckillGoods:" + goodsId);*/
                return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
            }
        }
        return RespBean.success(0);
    }

    @RequestMapping(value = "/secResult", method = RequestMethod.GET)
    @ResponseBody
    public RespBean getResult(@CaseUser UserBasic user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.NULL_USER_ERROR);
        }
        Long orderId = iSeckillOrderService.getResult(user, goodsId);
        if (orderId==1L){
            return RespBean.success(1);

        }else if (orderId==0L){
            return RespBean.success(0);

        }else if (orderId==-1L){
            return RespBean.error(RespBeanEnum.NULLGOODS_ERROR);
        }
        return RespBean.error(RespBeanEnum.OPRATION_ERROR);
    }

    @Override
    public void afterPropertiesSet() throws Exception {//这个类是用来初始化数据库里面的数据的
        List<GoodsVo> goodsVo = iGoodsService.findGoodsVo();
        if (CollectionUtils.isEmpty(goodsVo)) {
            return;
        }
        goodsVo.forEach(goodsVo1 -> {
            redisTemplate.opsForValue().set("seckillGoods:" + goodsVo1.getId(), goodsVo1.getStockCount());
            EmptyStockMap.put(goodsVo1.getId(), false);
        });
    }
}
